package common;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

public class FilesReader {

    private static class StringBlock {
        private String alias;
        private String after;
        private boolean dynamic;
        private boolean bad;
        private ArrayList<String> strs;

        public StringBlock(java.io.File file) throws IOException, ParseException {
            alias = file.getName().toUpperCase().replaceAll("\\W", "_");
            after = "";
            dynamic = true;
            bad = false;
            strs = new ArrayList<String>();

            BufferedReader reader;
            reader = new BufferedReader(new FileReader(file.getAbsolutePath()));
            String line = reader.readLine();
            if (line == null)
                return;
            // Убираем двойные пробелы и пробелы около знака =
            line = Strings.trimAndDelDoubleSpace(line);
            while (line.contains(" =") || line.contains("= "))
                line = Strings.replaceAll(line," =","=","= ","=");
            // Разбиваем первую строку по пробелу и смотрим входные параметры
            String[] fileParams = line.toUpperCase().split(" ");
            for (String fileParam : fileParams) {
                if (fileParam.startsWith("ALIAS")) {
                    if (fileParam.indexOf('=') <= 0)
                        throw new ParseException("В первой строке файла '" + file.getName() + "' у параметра 'alias' не найден знак '='");
                    alias = fileParam.substring(fileParam.indexOf('=') + 1, fileParam.length()).replaceAll("\\W", "_");
                    if (alias.length() == 0)
                        throw new ParseException("В первой строке файла '" + file.getName() + "' у параметра 'alias' не найдено значение");
                } else if (fileParam.startsWith("PARSE")) {
                    if (fileParam.indexOf('=') <= 0)
                        throw new ParseException("В первой строке файла '" + file.getName() + "' у параметра 'parse' не найден знак '='");
                    String ts = fileParam.substring(fileParam.indexOf('=') + 1, fileParam.length());
                    if (ts.length() == 0)
                        throw new ParseException("В первой строке файла '" + file.getName() + "' у параметра 'parse' не найдено значение");
                    if (ts.equals("BAD")) {
                        bad = true;
                        break;
                    } else if (ts.equals("DYNAMIC")) {
                        dynamic = true;
                    } else if (ts.equals("STATIC")) {
                        dynamic = false;
                    } else
                        throw new ParseException("В первой строке файла '" + file.getName() + "' у параметра 'parse' задано недопустимое значение: " + ts + " (Допустимо: dynamic, static и bad)");
                } else if (fileParam.startsWith("AFTER")) {
                    if (fileParam.indexOf('=') <= 0)
                        throw new ParseException("В первой строке файла '" + file.getName() + "' у параметра 'after' не найден знак '='");
                    after = fileParam.substring(fileParam.indexOf('=') + 1, fileParam.length()).replaceAll("\\W", "_");
                    if (after.length() == 0)
                        throw new ParseException("В первой строке файла '" + file.getName() + "' у параметра 'after' не найдено значение");
                } else
                    throw new ParseException("В первой строке файла '" + file.getName() + "' задан недопустимый параметр: " + fileParam.split("=")[0] + " (Допустимы: alias, parse и after)");
            }


            if (!bad) {
                // Разбиваем строки знаком ;; и каждую отдельную строку дописываем в массив строк
                while ((line = reader.readLine()) != null) {
                    if (!dynamic) {
                        strs.add(line);
                        continue;
                    }

                    ArrayList<String> tStrs = Strings.split(-1, line, ";", false, false);

                    // Считаем смещение первой строки
                    int spaces = Strings.getSpaceShift(tStrs.get(0));

                    // Добавляем первую строку
                    strs.add(Strings.getSpaceShift(spaces) + tStrs.get(0).trim());
                    // Добавляем остальные строки со смещением первой строки
                    for (int i = 1; i < tStrs.size(); i++)
                        strs.add(Strings.getSpaceShift(spaces) + tStrs.get(i).trim());
                }

                if (dynamic && strs.size() > 0) {
                    // Задаем отступы пустым строкам и комментариям равный отступу предыдущей строки
                    // Ищем первую комманду чтоб у пуст. строк и комментов стоящих в конце был правильный отступ
                    int n = strs.size() - 1;
                    for (; n >= 0; n--)
                        if (strs.get(n).trim().length() > 0 && !strs.get(n).trim().startsWith("//"))
                            break;
                    if (n < 0) {
                        for (int i = 0; i < strs.size(); i++)
                            strs.set(i, strs.get(i).trim());
                    } else {
                        int nShift = Strings.getSpaceShift(strs.get(n));
                        // Поправляем отступ у пуст. строк и комментов стоящих в конце
                        for (int i = strs.size() - 1; i > n; i--)
                            strs.set(i, Strings.getSpaceShift(nShift) + strs.get(i).trim());
                        // Выравниваем остальные отступы у пуст. строк и комментов
                        for (; n >= 0; n--) {
                            if (strs.get(n).trim().length() > 0 && !strs.get(n).trim().startsWith("//"))
                                nShift = Strings.getSpaceShift(strs.get(n));
                            else
                                strs.set(n, Strings.getSpaceShift(nShift) + strs.get(n).trim());
                        }
                    }

                    /* Выравниваем все строки вида:

                            1
                                2
                        3
                            4
                    5
                        6

                    К виду

                    1
                        2
                    3
                        4
                    5
                        6
                    */
                    int findLastIndex = strs.size();
                    while (findLastIndex > 0) {
                        int minShift = Strings.getSpaceShift(strs.get(0));
                        int minShiftPos = 0;

                        for (int i = 0; i < findLastIndex; i++) {
                            int tShift = Strings.getSpaceShift(strs.get(i));
                            if (tShift < minShift) {
                                minShift = tShift;
                                minShiftPos = i;
                            }
                        }

                        if (minShift > 0)
                            for (int i = 0; i < findLastIndex; i++)
                                strs.set(i, strs.get(i).substring(minShift));

                        findLastIndex = minShiftPos;
                    }
                }
            }

            // Добавляем коммент в каждый блок строк
            strs.add(0, "//");
            strs.add(0, "// =======================================================================");
            strs.add(0, "// Alias:" + alias + "  After:" + after + "  Type:" + ((bad) ? "BAD" : ((dynamic) ? "DYNAMIC" : "STATIC")));
            strs.add(0, "// =======================================================================");
        }

        public boolean isBad() {
            return bad;
        }

        public String getAlias() {
            return alias;
        }

        public String getAfter() {
            return after;
        }

        public ArrayList<String> getStrs() {
            return strs;
        }
    }

    /* CLASS CLASS CLASS CLASS CLASS CLASS CLASS CLASS CLASS CLASS CLASS CLASS CLASS */

    private static ArrayList<StringBlock> strBlocks = new ArrayList<StringBlock>();

    public static ArrayList<String> getStrings(String basePath) throws IOException, ParseException {
        // Поиск в папках и подпапках
        java.io.File folder = new java.io.File(basePath);
        findFiles(folder);

        ArrayList<String> strs = new ArrayList<String>();
        for (StringBlock block : strBlocks)
            strs.addAll(block.getStrs());

        return strs;
    }

    private static void findFiles(java.io.File folder) throws IOException, ParseException {
        for (java.io.File f : folder.listFiles())
            if (f.isFile()) {
                if (f.getName().toLowerCase().endsWith(".mif")) {
                    StringBlock strBlock = new StringBlock(f);
                    if (!strBlock.isBad())
                        strBlocks.add(strBlock);
                }
            } else if (f.isDirectory())
                findFiles(f.getAbsoluteFile());
    }
}
